/*-------------------------------------------------------------------
*
* Filename: wf_file_util.cpp
* Description: 
*     
*
* Version:1.0
* Create date: 10/10/2004
* Revise date: 03/22/2007
* Author: walter.fan@gmail.com
*--------------------------------------------------------------------*/
#include <sys/types.h>
#include <signal.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include "wf_file_util.h"
#include "wf_string_util.h"

using namespace std;
const int BUFLEN=256;

//-----------------class Csv--------------//
// endofline: check for and consume \r, \n, \r\n, or EOF
int Csv::endofline(char c)
{
    int eol;

    eol = (c=='\r' || c=='\n');
    if (c == '\r') {
        fin.get(c);
        if (!fin.eof() && c != '\n')
            fin.putback(c); // read too far
    }
    return eol;
}

// getline: get one line, grow as needed
int Csv::getline(string& str)
{   
    char c;

    for (line = ""; fin.get(c) && !endofline(c); )
        line += c;
    split();
    str = line;
    return !fin.eof();
}

// split: split line into fields
int Csv::split()
{
    string fld;
    u_int i, j;

    nfield = 0;
    if (line.length() == 0)
        return 0;
    i = 0;

    do {
        if (i < line.length() && line[i] == '"')
            j = advquoted(line, fld, ++i);  // skip quote
        else
            j = advplain(line, fld, i);
        if (nfield >= field.size())
            field.push_back(fld);
        else
            field[nfield] = fld;
        nfield++;
        i = j + 1;
    } while (j < line.length());

    return nfield;
}

// advquoted: quoted field; return index of next separator
int Csv::advquoted(const string& s, string& fld, u_int i)
{
    u_int j;

    fld = "";
    for (j = i; j < s.length(); j++) {
        if (s[j] == '"' && s[++j] != '"') {
            u_int k = s.find_first_of(fieldsep, j);
            if (k > s.length()) // no separator found
                k = s.length();
            for (k -= j; k-- > 0; )
                fld += s[j++];
            break;
        }
        fld += s[j];
    }
    return j;
}

// advplain: unquoted field; return index of next separator
int Csv::advplain(const string& s, string& fld, u_int i)
{
    u_int j;

    j = s.find_first_of(fieldsep, i); // look for separator
    if (j > s.length())               // none found
        j = s.length();
    fld = string(s, i, j-i);
    return j;
}


// getfield: return n-th field
string Csv::getfield(u_int n)
{
    if (n < 0 || n >= nfield)
        return "";
    else
        return field[n];
}

//------------class CFileUtil-------------------//
int Cwf_file_util::CreateDir(const char * pDir)
{
    if(!pDir)
        return -1;

    struct stat stDir;
    int ret = stat(pDir , &stDir);
    
    if(ret == -1 && errno == ENOENT)
        return mkdir(pDir , 0777);
    else if(ret == 0)
    {    
        int ret = S_ISDIR(stDir.st_mode);
        if(!ret)
        {
            char szTmpName[BUFLEN];
            snprintf(szTmpName,BUFLEN, "%s.bak" , pDir);
            rename(pDir , szTmpName);
            return mkdir(pDir ,0777);
        }
        else
            return 0;
    }
    return -1;
}

void Cwf_file_util::WriteSymLink(const char *target,const char *linkname)
{
    if(!target||!linkname)
        return;
    if(symlink(target,linkname)==-1&&errno==EEXIST)
    {
        char szTarget[BUFLEN];
        int num=0;
        num=readlink(linkname, szTarget, BUFLEN);
        if(num<=0||strncmp(target,szTarget,num)!=0)
        {
            unlink(linkname);
            symlink(target,linkname);
        }
    }

}

bool Cwf_file_util::IsFileExists( const char *path )
{
    if(!path)
        return false;
    FILE *fp ;
    if( ( fp = fopen( path, "rb" ) ) == NULL )
        return false;
    fclose( fp ) ;
    return true ;
}

bool Cwf_file_util::IsDirExists( const char *path )
{
    if(!path)
        return false;
    DIR* pDir = NULL;
    pDir = opendir(path);
    if(pDir)
    {    
        closedir(pDir);
        return true;
    }
    else
        return false;
}

bool Cwf_file_util::IsThisKindFile(string strfile,const char* suffix)
{    
	string::size_type nPos1=strfile.find(suffix);
	if (nPos1 == string::npos)
		return false;
	else
		return true;
}


int Cwf_file_util::GetStatus(const char* pszCmd,const char* pszPid)
{
    if(!pszCmd||!pszPid)
        return -1;
    //debug_trace("cmd="<<pszCmd<<",pidfile="<<pszPid);
    ifstream pidfile(pszPid);
    
    if(!pidfile)
        return 0;//not started

    string textline;
    int oldpid;
    char szStatFile[BUFLEN]="";
    char szCmdName[BUFLEN]="";
    GetFileName(pszCmd, szCmdName, BUFLEN);

    getline(pidfile,textline,'\n');
    string strpid=Trim(textline);
    oldpid=atoi(strpid.c_str());
    if (kill (oldpid, 0) == -1 && errno == ESRCH)
            return -1;//CRASHED;
    else
    {
        snprintf(szStatFile ,BUFLEN, "/proc/%d/stat" , oldpid);
        snprintf(szCmdName ,BUFLEN, "(%s)" , szCmdName);    
        ifstream statfile(szStatFile);
        if(!statfile)
        return 0;//not started
           else
           {
               getline(statfile,textline,'\n');
               if(textline.find(szCmdName))
                      return 1;//alive
                else
                      return -1;//crashed
            }
    }
}


off_t Cwf_file_util::GetFileSize(const char* pszFile)
{
    if(!pszFile)
        return -1;
    int retval=0;
    struct stat statBuf;
    retval=stat(pszFile,&statBuf);
    if(retval<0)    
        return -1;
    return statBuf.st_size;

}

int Cwf_file_util::GetFileName(const char *path, char *buffer, size_t size)
{
    if(!path||!buffer)
        return -1;
    const char *cp = strrchr(path, SEPARATOR);

    if(cp)
        snprintf(buffer, size, "%s", ++cp);
    else
    {    
        snprintf(buffer, size, "%s", path);
        return -1;
    }

    return 0;
}

int Cwf_file_util::GetDirName(const char *path, char *buffer, size_t size)
{
    if(!path||!buffer)
        return -1;
    
    size_t len;
    const char *cp = strrchr(path, SEPARATOR);

    if(cp)
        len = cp - path;
    else
        return -1;
    
    snprintf(buffer, size, "%s", path);

    if(len >= size)
        len = size - 1;
    buffer[len] = '\0';
    return 0;
}

int Cwf_file_util::CopyFile(const char* szSrc,const char* szDest)
{
    char ch;
    FILE * fp1=NULL;
    FILE * fp2=NULL;

    if((fp1=fopen(szSrc,"rb"))==NULL)
    {
        err_trace("\nCant open file "<<szSrc);
        //fclose(fp1);
        return -1;
    }
    
    if((fp2=fopen(szDest,"wb"))==NULL)
    {
        err_trace("\nCant open file "<<szDest);
        fclose(fp1);
        return -1;
    }

    ch=fgetc(fp1);
    while (!feof(fp1))
    {
        fputc(ch,fp2);
        ch=fgetc(fp1);
    }
    
    fclose(fp1);
    fclose(fp2);
    return 0;
} 

int Cwf_file_util::ParseCsv(char* pCsvFile,csv_lines_t& lines)
{
    ifstream infs(pCsvFile);
    if(!infs)
    {
        err_trace("Unable to find "<<pCsvFile);
        return -1;
    }    
    string line="";
    Csv csv(infs);
	while (csv.getline(line) != 0) 
    {
		//cout << "line = `" << line <<"'\n";
        vector<string> strvec;
		for (int i = 0; i < csv.getnfield(); i++)
		{	
		    //cout << "field[" << i << "] = `"	 << csv.getfield(i) << "'\n";
            strvec.push_back(csv.getfield(i));
        }
        if(!strvec.empty())
            lines.push_back(strvec);
	}
    
    infs.close();    
    return 0;
}

int Cwf_file_util::mkdir_if_not_exists(const char * pDir)
{
	struct stat stDir;
	int ret = stat(pDir , &stDir);

	if(ret == -1 && errno == ENOENT)
		return mkdir(pDir , 0777);
	else if(ret == 0)
	{
		int ret = S_ISDIR(stDir.st_mode);
		if(!ret)
		{
			char szTmpName[BUFLEN];
			snprintf(szTmpName,BUFLEN, "%s.bak" , pDir);
			rename(pDir , szTmpName);
			return mkdir(pDir ,0777);
		}
		else
			return 0;
	}
	return -1;
}


